Skip to content

Port Air Simulation TUI into Public Repo#17

Draft
zsblevins wants to merge 4 commits into
mainfrom
port-air
Draft

Port Air Simulation TUI into Public Repo#17
zsblevins wants to merge 4 commits into
mainfrom
port-air

Conversation

@zsblevins
Copy link
Copy Markdown
Collaborator

@zsblevins zsblevins commented May 30, 2026

Description

  • Ports the Air Simulation TUI into the public repo
  • Adds a user guide
  • Deletes all the deprecated AirV1 Workflows

Validation

  • Standard CI passes.
  • Kind integration passes, or this PR explains why it was not run.

Checklist

  • I am familiar with the contributing guidelines in CONTRIBUTING.md.
  • Commits are signed off for DCO compliance.
  • New or existing tests cover these changes, or the PR explains why tests are not needed.
  • Documentation is updated for user-facing behavior changes.
  • Generated artifacts are updated when applicable, such as OpenAPI specs,
    docs screenshots, or Helm/rendered outputs.

Summary by CodeRabbit

  • New Features

    • Added AIR Simulation TUI and CLI for provisioning demo topologies with virtual Cumulus switches.
    • Introduced superpod template plugin with support for SpectrumX and VXLAN configurations.
  • Documentation

    • Added comprehensive AIR Simulation User Guide with tutorials and workflow examples.
    • Updated installation guides to reference new nvcm-installer command alias.
  • Chores

    • Renamed installer command from nv-config-manager-installer to nvcm-installer for brevity.
    • Removed legacy AIR SDK integrations and updated mock topologies for trial and superpod scenarios.

Review Change Stack

zsblevins added 3 commits May 30, 2026 01:44
Signed-off-by: Zoe Blevins <zblevins@nvidia.com>
Signed-off-by: Zoe Blevins <zblevins@nvidia.com>
…generator

Signed-off-by: Zoe Blevins <zblevins@nvidia.com>
@copy-pr-bot
Copy link
Copy Markdown

copy-pr-bot Bot commented May 30, 2026

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 30, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 7f1a1433-aa5c-4af8-a413-37ed5ea90869

📥 Commits

Reviewing files that changed from the base of the PR and between 7b9b118 and 1174e55.

📒 Files selected for processing (28)
  • .github/copilot-instructions.md
  • .gitignore
  • development/mock_topology/context/air_superpod/devices/su00-cin-spine01.json
  • development/mock_topology/context/air_superpod/devices/su00-cin-spine02.json
  • development/mock_topology/context/air_superpod/devices/su00-tan-spine01.json
  • development/mock_topology/context/air_superpod/devices/su00-tan-spine02.json
  • development/mock_topology/context/air_superpod/devices/su01-cin-leaf-r01.json
  • development/mock_topology/context/air_superpod/devices/su01-cin-leaf-r02.json
  • development/mock_topology/context/air_superpod/devices/su01-tan-bleaf01.json
  • development/mock_topology/context/air_superpod/devices/su01-tan-bleaf02.json
  • development/mock_topology/context/air_superpod/devices/su01-tan-hleaf01.json
  • development/mock_topology/context/air_superpod/devices/su01-tan-hleaf02.json
  • development/mock_topology/context/air_superpod/devices/su01-tan-sleaf01.json
  • development/mock_topology/context/air_superpod/devices/su01-tan-sleaf02.json
  • development/mock_topology/jobs/mock_topology_design.py
  • docs/user-guides/air-simulation/index.mdx
  • installer/src/nv_config_manager_installer/air_sim/cli.py
  • installer/src/nv_config_manager_installer/air_sim/cloud_init.py
  • installer/src/nv_config_manager_installer/air_sim/constants.py
  • installer/src/nv_config_manager_installer/air_sim/sim_manager.py
  • installer/src/nv_config_manager_installer/air_sim/topology.py
  • installer/src/nv_config_manager_installer/deployer.py
  • installer/src/nv_config_manager_installer/tui/air_sim/app.py
  • installer/src/nv_config_manager_installer/tui/air_sim/screens/launch.py
  • installer/src/nv_config_manager_installer/tui/air_sim/screens/options.py
  • installer/tests/air_sim/test_tui_launch.py
  • installer/tests/test_deployer.py
  • src/tests/development/test_mock_topology_context.py
✅ Files skipped from review due to trivial changes (9)
  • .gitignore
  • development/mock_topology/context/air_superpod/devices/su01-tan-bleaf02.json
  • development/mock_topology/context/air_superpod/devices/su01-tan-sleaf02.json
  • development/mock_topology/context/air_superpod/devices/su01-cin-leaf-r01.json
  • development/mock_topology/context/air_superpod/devices/su00-cin-spine02.json
  • .github/copilot-instructions.md
  • development/mock_topology/context/air_superpod/devices/su00-cin-spine01.json
  • development/mock_topology/context/air_superpod/devices/su01-tan-sleaf01.json
  • docs/user-guides/air-simulation/index.mdx
🚧 Files skipped from review as they are similar to previous changes (13)
  • development/mock_topology/context/air_superpod/devices/su01-cin-leaf-r02.json
  • development/mock_topology/context/air_superpod/devices/su00-tan-spine01.json
  • installer/src/nv_config_manager_installer/air_sim/constants.py
  • installer/tests/air_sim/test_tui_launch.py
  • installer/src/nv_config_manager_installer/deployer.py
  • installer/src/nv_config_manager_installer/air_sim/cli.py
  • development/mock_topology/jobs/mock_topology_design.py
  • installer/tests/test_deployer.py
  • installer/src/nv_config_manager_installer/tui/air_sim/screens/launch.py
  • installer/src/nv_config_manager_installer/tui/air_sim/app.py
  • installer/src/nv_config_manager_installer/air_sim/cloud_init.py
  • installer/src/nv_config_manager_installer/air_sim/topology.py
  • installer/src/nv_config_manager_installer/air_sim/sim_manager.py

📝 Walkthrough

Walkthrough

Adds an AIR Simulation TUI/CLI and orchestrator with mock contexts/templates, parallelizes image builds, renames installer to nvcm-installer, updates docs/tests, modifies bootstrap content_types behavior, and removes legacy AIR API/workflows/Helm secrets/values.

Changes

AIR Simulation enablement and AIR deprecation

Layer / File(s) Summary
AIR Sim tooling (TUI/CLI/orchestrator/cloud-init/topology/proxy)
installer/src/nv_config_manager_installer/air_sim/*, installer/src/nv_config_manager_installer/tui/air_sim/*, installer/scripts/screenshot_air_sim_tui.py, development/air_sim/*
Adds AIR Sim app/screens/styles, CLI commands, orchestrator, cloud-init, topology builders, proxy, prebuilt configs, and screenshot generator.
Mock contexts and templates
development/mock_topology/**/*, development/air_sim/template_plugins/superpod-template-plugin/**/*
Introduces AIR trial/superpod mock device/location/prefix data and Superpod template plugin includes/entrypoints.
Installer updates and parallel builds
installer/pyproject.toml, installer/src/*/cli.py, installer/src/*/deployer.py, Makefile, docs
Renames CLI to nvcm-installer, registers subcommands, adds parallel docker builds, and documents screenshot workflow and new commands.
Deprecate legacy AIR integration
src/nv_config_manager/temporal/**/*air*, docs/api-specs/temporal.openapi.json, Helm templates/values
Removes AIR client, activities, workflows, API endpoints, Helm AIR secrets/values.
Bootstrap and tests
components/nautobot/*bootstrap*, components/nautobot/tests/*, installer/tests/**/*
Switches content_types updates to additive, updates and adds tests for new behaviors and tooling.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant TUI (AIR Sim)
  participant Orchestrator
  participant AIR Service
  participant NVCM Server

  User->>TUI (AIR Sim): Configure + Launch
  TUI (AIR Sim)->>Orchestrator: Run(config)
  Orchestrator->>AIR Service: Create simulation + attach cloud-init
  AIR Service-->>Orchestrator: SSH host:port
  Orchestrator->>NVCM Server: Upload install.yaml + Deploy (SSH)
  NVCM Server-->>Orchestrator: Status/logs
  Orchestrator-->>TUI (AIR Sim): Step updates + access info
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Suggested reviewers

  • ryanheffernan
  • jojung1
  • spidercensus
  • dmathur0

Poem

A rabbit pressed “Launch” with a wink and a grin,
Spun clouds into kind, let the packets begin.
Through SOCKS it burrowed, to Nautobot’s door,
Pods blinked “Ready!”—four, then six, then more.
With nvcm-installer, it hopped to deploy—
Simulated switches, real rabbit joy!

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch port-air

@zsblevins
Copy link
Copy Markdown
Collaborator Author

/ok to test 7b9b118

@zsblevins zsblevins marked this pull request as draft May 30, 2026 02:57
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 20

Note

Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.

🟡 Minor comments (3)
development/mock_topology/context/air_superpod/devices/su00-tan-spine01.json-61-117 (1)

61-117: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fix duplicate eth0 interface entries (overwrite risk) in su00-tan-spine01.json
This JSON defines two interfaces with the same name (eth0), same mac_address, same ip_addresses, and same connected_interface, differing only in fields like mgmt_only/role. The generator development/mock_topology/jobs/designs/interfaces.yaml.j2 keys interfaces by !create_or_update:name and !ref:intf-{{ device.name }}-{{ intf.name }}, so both entries target the same interface object and will overwrite each other. Collapse to a single eth0 entry (keep the intended mgmt_only/role).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@development/mock_topology/context/air_superpod/devices/su00-tan-spine01.json`
around lines 61 - 117, The file contains two duplicate interface objects named
"eth0" (same mac_address, ip_addresses, connected_interface) which will collide
because the generator (interfaces.yaml.j2) keys interfaces by
!create_or_update:name and !ref:intf-{{ device.name }}-{{ intf.name }}; collapse
these into a single "eth0" object by merging the differing fields (choose the
correct mgmt_only and role values you intend to keep, e.g., mgmt_only: true vs
false and include the role: { name: "Management" } if needed), remove the
duplicate entry, and ensure the resulting interface includes name, type, status,
enabled, mgmt_only, ip_addresses, mac_address, description/mtu/role as required
and the same connected_interface block so there is no overwrite during
generation.
installer/src/nv_config_manager_installer/air_sim/sim_manager.py-414-416 (1)

414-416: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Return type contract is violated in prepare_server().

The method is annotated str | None, but Line 465 returns False. This introduces mixed return semantics and can cause incorrect callers.

💡 Suggested fix
-                return False
+                return None

Also applies to: 465-466

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@installer/src/nv_config_manager_installer/air_sim/sim_manager.py` around
lines 414 - 416, prepare_server currently declares a return type of "str | None"
but returns a boolean False in some failure paths; change those failure returns
to None (or alternatively change the annotation to "str | bool" if boolean
semantics are intentional) so the return type contract is consistent; locate the
prepare_server function and replace any "return False" (and similar boolean
returns) with "return None", and run a quick grep for callers of prepare_server
to adjust any truthy/falsey checks to explicit None checks if needed.
installer/src/nv_config_manager_installer/tui/air_sim/screens/options.py-158-165 (1)

158-165: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Consider providing user feedback for invalid timeout values.

The silent ValueError handling preserves the existing config value when the user enters invalid input, but provides no indication that the input was rejected. Users might be confused when their changes don't take effect.

💡 Suggested improvement

Consider using Textual's validation system or showing a notification when integer parsing fails:

try:
    config.wait_timeout = int(self.query_one("`#wait-timeout`", Input).value)
except ValueError:
    self.app.notify("Invalid wait timeout - must be an integer", severity="warning")
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@installer/src/nv_config_manager_installer/tui/air_sim/screens/options.py`
around lines 158 - 165, The current try/except blocks around reading
"`#wait-timeout`" and "`#deploy-timeout`" swallow ValueError silently; update the
handlers in the method where you call self.query_one("`#wait-timeout`", Input) and
self.query_one("`#deploy-timeout`", Input) so that when int(...) raises ValueError
you preserve the existing config value but also surface feedback to the user
(e.g., call self.app.notify or use Textual validation) with a clear message like
"Invalid wait timeout — must be an integer" and "Invalid deploy timeout — must
be an integer" so users know their input was rejected; keep the existing
behavior of not overwriting config but add the notification in the except blocks
for both config.wait_timeout and config.deploy_timeout.
🧹 Nitpick comments (1)
development/mock_topology/jobs/mock_topology_design.py (1)

92-99: ⚡ Quick win

Consider logging invalid content type strings.

The method silently returns None for invalid content type strings. Configuration errors (typos, missing models) will be silently ignored. Consider logging a warning when ValueError or ContentType.DoesNotExist is caught to aid debugging.

📝 Suggested enhancement
+import logging
+
+logger = logging.getLogger(__name__)
+
 `@staticmethod`
 def _get_content_type(content_type: str) -> ContentType | None:
     """Resolve an app.model content type string."""
     try:
         app_label, model = content_type.split(".")
         return ContentType.objects.get(app_label=app_label, model=model)
     except (ValueError, ContentType.DoesNotExist):
+        logger.warning("Invalid content type string: %s", content_type)
         return None
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@development/mock_topology/jobs/mock_topology_design.py` around lines 92 - 99,
The _get_content_type function currently swallows ValueError and
ContentType.DoesNotExist; modify it to log a warning including the invalid
content_type string and the exception details before returning None. Use a
module logger (e.g., logger = logging.getLogger(__name__)) or an existing logger
and call logger.warning(...) inside the except block, referencing the caught
exception and the content_type variable; keep the existing return None behavior.
Ensure you import logging if not present and catch both ValueError and
ContentType.DoesNotExist in the same except to log them.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@development/mock_topology/context/air_superpod/devices/su00-cin-spine01.json`:
- Around line 61-117: There are two duplicate interface objects named "eth0" on
this device (both using address 10.100.1.25/25, same MAC and connected peer
su01-oob-mleaf01:swp6) which will conflict in Nautobot and evade the
_require_cumulus_eth0_mac validator that only checks the first match; remove the
redundant entry and keep the fuller definition (the one with mgmt_only:false
plus role/mtu/description) or merge any needed fields into that single eth0
object so only one eth0 interface exists for the device.

In
`@development/mock_topology/context/air_superpod/devices/su00-cin-spine02.json`:
- Around line 61-117: Remove the redundant eth0 interface entry: there are two
interface objects with "name": "eth0" (both using IP 10.100.1.149/25, MAC
44:38:39:00:00:03 and connected_interface su01-oob-mleaf02:swp6); keep the
intended single definition (prefer the one with the desired fields such as
"mgmt_only": false, "description", "mtu", "role") and delete the other block so
the device has only one eth0 entry and no duplicate IP/MAC/peer config.

In
`@development/mock_topology/context/air_superpod/devices/su01-tan-bleaf01.json`:
- Around line 61-117: The interfaces array contains two entries both named
"eth0" with identical IP 10.100.1.19/25, MAC 44:38:39:00:00:13 and
connected_interface swp3 -> device su01-oob-mleaf01; remove the duplicate by
either merging the two objects into a single interface entry for "eth0"
(combining fields like mgmt_only, description, mtu, role) or rename one entry to
a distinct interface name (e.g., "eth1" or "eth0:mgmt") and update its fields
accordingly so each interface name is unique.

In
`@development/mock_topology/context/air_superpod/devices/su01-tan-bleaf02.json`:
- Around line 61-117: The interfaces array contains two entries with the same
"name": "eth0" (both have address 10.100.1.146/25, mac_address 44:38:39:00:00:14
and connected_interface.name "swp3"), which must be merged or renamed; update
the JSON so there is only one unique interface entry for "eth0" by consolidating
fields (combine mgmt_only, enabled, description, mtu, role, ip_addresses and
connected_interface) into a single object (or rename the second entry to a
distinct interface name if it represents a different logical interface) ensuring
no duplicated IPs/MACs and preserving connected_interface.device/role
information.

In
`@development/mock_topology/context/air_superpod/devices/su01-tan-hleaf01.json`:
- Around line 61-117: The interfaces array contains two entries with the same
name "eth0" (both with address 10.100.1.21/25 and MAC 44:38:39:00:00:15), which
is invalid; resolve by merging the two objects into a single "eth0" entry that
combines differing fields (e.g., include mgmt_only, description, mtu, role) or
by renaming one entry to a unique interface name (and adjust its
description/role accordingly), ensuring there is only one "name": "eth0" object
and that IP, mac, connected_interface, and role fields are consistent and not
duplicated.

In
`@development/mock_topology/context/air_superpod/devices/su01-tan-hleaf02.json`:
- Around line 61-117: There are two interface objects both named "eth0" with
identical IP/MAC/connected_interface but conflicting mgmt_only values; remove or
merge the duplicate so each interface name is unique: pick the correct mgmt_only
value (true or false) and consolidate properties into a single "eth0" entry
(preserve fields like ip_addresses, mac_address, mtu, description, role,
connected_interface) or rename one interface if both are needed; update the
object that currently contains "name": "eth0" to remove the duplicate and ensure
only one interface object with that name remains.

In
`@development/mock_topology/context/air_superpod/devices/su01-tan-sleaf01.json`:
- Around line 61-117: The JSON defines the same interface name "eth0" twice with
identical IP/MAC/connected_interface but conflicting mgmt_only and other
properties; remove or merge the duplicate so only one "eth0" entry exists:
either delete the redundant block (the second or first) or merge fields into a
single object for "eth0" preserving the correct values for mgmt_only,
description, mtu, role, ip_addresses, mac_address and connected_interface;
ensure the final interface object uses the unique name "eth0" and consistent
properties to avoid validation/parsing errors.

In
`@development/mock_topology/context/air_superpod/devices/su01-tan-sleaf02.json`:
- Around line 61-117: There are two interface objects both named "eth0" with
identical ip_addresses, mac_address and connected_interface but conflicting
mgmt_only values; fix by merging these into a single "eth0" entry (or remove the
duplicate) so only one interface object exists, consolidate fields
(ip_addresses, mac_address, connected_interface, description, mtu, role) into
that single "eth0" object and set mgmt_only to the correct boolean value you
intend to model.

In `@installer/nvcm-air-sim.yaml`:
- Line 24: Replace the hardcoded NGC API key value for ngc_api_key in the YAML
(the line setting ngc_api_key) with a reference to a secrets source (e.g., an
environment variable or placeholder) and remove the literal token from the repo;
update any deployment/config loading to read process.env.NGC_API_KEY (or your
secret manager) and add a non-sensitive example entry (e.g.,
NGc_API_KEY=REPLACE_ME) to your env/sample file or docs so users know how to
supply the key, and ensure you scan for and remove any other hard-coded
credentials.

In `@installer/src/nv_config_manager_installer/air_sim/cloud_init.py`:
- Line 294: The FRR config template currently hardcodes the BGP password
"NVCMBgp1!" in _SETUP_SCRIPT_TEMPLATE; change the template to use a placeholder
(e.g. {bgp_password}) instead of the literal string, and update
generate_setup_script to substitute NVCM_NETWORK_SECRETS["bgp_password"] into
that placeholder before returning the script, ensuring the template uses the
placeholder and generate_setup_script imports/reads NVCM_NETWORK_SECRETS and
performs a safe format/replace to inject the secret into the
_SETUP_SCRIPT_TEMPLATE.
- Around line 334-366: The download loop for node_exporter (uses variables
tarball, gh_arch, NE_VERSION, NE_BASE, NE_DIR and temp file "/tmp/${tarball}")
does not verify integrity against the hardcoded SHA256 values in the manifest;
after each curl download compute the SHA256 of "/tmp/${tarball}" (eg via
sha256sum or shasum -a 256) and compare it to the expected checksum for that
arch (the values currently embedded in the jq manifest for node_exporter_amd64
and node_exporter_armv5), abort with a non‑zero exit and log an error if the
checksums differ, and only proceed to tar/x extract and mv the binary when the
checksum matches (also ensure you remove the temp file on failure). Ensure the
checksum lookup maps gh_arch or out_name to the correct expected hash before
comparing so the correct manifest value is used.
- Around line 539-542: The script currently injects unescaped dynamic values via
script.replace("__OOB_SWITCH_GW__", oob_gateway or "UNSET") and similar replaces
for "__LB_ALLOWED_PREFIXES__", "__RELAY_RETURN_NETWORKS__", and "__BGP_ASN__",
which risks shell injection; fix by importing shlex and wrapping each
substituted value with shlex.quote(...) (ensure the fallback "UNSET" is quoted
as well) before calling script.replace so all dynamic inputs are safely
shell-escaped.

In `@installer/src/nv_config_manager_installer/air_sim/sim_manager.py`:
- Around line 1342-1344: The public method currently hard-codes a default
password ("demo") in the signature (the parameters username, password, namespace
where CONFIG_MANAGER_NAMESPACE is used); remove the hard-coded default by making
password (and optionally username) required (or default to None) and add a
runtime validation that raises a clear exception if password is not provided, or
pull the value from a secure source (env var or secret manager) instead; update
all callers of this method to pass credentials and ensure documentation/comments
note the required parameter change so callers are fixed accordingly.
- Around line 525-527: Remove the hard-coded BGP password string "neighbor {gw}
password NVCMBgp1!" in sim_manager.py and instead inject the BGP password from a
secret/config input; e.g., add a parameter or read from a secrets/config object
(bgp_password) or environment variable (BGP_PASSWORD) in the function that
builds the FRR config where the neighbor {gw} lines are composed, replace the
literal with that variable, ensure the secret is sourced from your secret
manager or rotated per run, and avoid printing or logging the password.
- Around line 480-481: The route calculation currently slices internal_ip
assuming a /24; replace that with proper CIDR math using Python's ipaddress
module: parse internal_ip with ipaddress.ip_network(internal_ip, strict=False),
derive the canonical network as f"{net.network_address}/{net.prefixlen}" (or
str(net)), assign that to internal_network, and then call _ssh exactly as before
with iface_name; use strict=False to allow host addresses to resolve to their
correct network. Ensure you import ipaddress at top of sim_manager.py and update
the internal_network assignment where it currently uses rsplit and split.

In `@installer/src/nv_config_manager_installer/air_sim/topology.py`:
- Around line 301-315: The code calls description.lower() assuming description
is a string (description = intf.get("description", "")) but YAML null yields
None; update the handling so description is coerced to a string or validated
before calling .lower() — e.g., after reading description from intf, set
description = description if isinstance(description, str) else "" (or
description = (intf.get("description") or "")), then use description.lower()
when checking for "exit"; this change affects the block where description,
raw_mac, mac_address, needs_auto are computed and where
self.exit_interfaces.append((device_name, intf_name)) is conditional.

In `@installer/src/nv_config_manager_installer/deployer.py`:
- Around line 893-906: The code builds a docker command using build_output_args
created from build_env["BUILDX_BUILDER"] and then constructs the command in the
_ParallelCommand for each entry in images, but it erroneously appends --load to
a plain docker build; update the logic around build_output_args and the command
construction so that when build_env.get("BUILDX_BUILDER") is truthy you either
switch the invoked binary to "docker buildx build" (i.e., use "docker",
"buildx", "build", ... and include "--load") or keep "docker", "build" and
remove "--load" (or use "--output=type=docker" instead); adjust the code that
builds the cmd list inside the loop that creates _ParallelCommand (and the
build_output_args assignment) so the CLI flags match the chosen command (search
for build_output_args, build_env, images, and _ParallelCommand to find where to
change).

In `@installer/src/nv_config_manager_installer/tui/air_sim/screens/launch.py`:
- Around line 772-780: The method _do_prov_refresh uses assert
isinstance(self._manager, AirSimulationManager) for a runtime check; replace
that assert with an explicit check (e.g., if not isinstance(self._manager,
AirSimulationManager): raise TypeError(...) or log an error and return) before
calling self._manager.get_provisioning_status(self._host, self._port), so the
code fails predictably when _manager is the wrong type and still reaches the
finally block that clears self._prov_polling; reference _do_prov_refresh,
_manager, AirSimulationManager, get_provisioning_status, _update_prov,
_prov_polling, _host, and _port when making the change.
- Around line 893-900: In _run_orchestrator, the conditional used for the
context manager should choose the pathname before calling open rather than
between two open calls; replace the current conditional expression with one that
passes the chosen path to open (e.g., open(log_path if log_path else os.devnull,
"w") as lf) so the with statement consistently binds lf to the opened file, then
construct _TuiCallback(self, log_file=lf) and pass it to
SimOrchestrator(self._config, cb).
- Around line 762-770: Replace the runtime assert in _do_refresh with an
explicit isinstance check: verify that self._manager is an AirSimulationManager
before calling get_pod_status; if the check fails, either raise a descriptive
TypeError (e.g., "expected AirSimulationManager for self._manager") or log the
error and return early to avoid calling get_pod_status with the wrong type, then
proceed to call self._manager.get_pod_status(self._host, self._port) and
self.app.call_from_thread(self._update_table, pods) when the check passes.

---

Minor comments:
In
`@development/mock_topology/context/air_superpod/devices/su00-tan-spine01.json`:
- Around line 61-117: The file contains two duplicate interface objects named
"eth0" (same mac_address, ip_addresses, connected_interface) which will collide
because the generator (interfaces.yaml.j2) keys interfaces by
!create_or_update:name and !ref:intf-{{ device.name }}-{{ intf.name }}; collapse
these into a single "eth0" object by merging the differing fields (choose the
correct mgmt_only and role values you intend to keep, e.g., mgmt_only: true vs
false and include the role: { name: "Management" } if needed), remove the
duplicate entry, and ensure the resulting interface includes name, type, status,
enabled, mgmt_only, ip_addresses, mac_address, description/mtu/role as required
and the same connected_interface block so there is no overwrite during
generation.

In `@installer/src/nv_config_manager_installer/air_sim/sim_manager.py`:
- Around line 414-416: prepare_server currently declares a return type of "str |
None" but returns a boolean False in some failure paths; change those failure
returns to None (or alternatively change the annotation to "str | bool" if
boolean semantics are intentional) so the return type contract is consistent;
locate the prepare_server function and replace any "return False" (and similar
boolean returns) with "return None", and run a quick grep for callers of
prepare_server to adjust any truthy/falsey checks to explicit None checks if
needed.

In `@installer/src/nv_config_manager_installer/tui/air_sim/screens/options.py`:
- Around line 158-165: The current try/except blocks around reading
"`#wait-timeout`" and "`#deploy-timeout`" swallow ValueError silently; update the
handlers in the method where you call self.query_one("`#wait-timeout`", Input) and
self.query_one("`#deploy-timeout`", Input) so that when int(...) raises ValueError
you preserve the existing config value but also surface feedback to the user
(e.g., call self.app.notify or use Textual validation) with a clear message like
"Invalid wait timeout — must be an integer" and "Invalid deploy timeout — must
be an integer" so users know their input was rejected; keep the existing
behavior of not overwriting config but add the notification in the except blocks
for both config.wait_timeout and config.deploy_timeout.

---

Nitpick comments:
In `@development/mock_topology/jobs/mock_topology_design.py`:
- Around line 92-99: The _get_content_type function currently swallows
ValueError and ContentType.DoesNotExist; modify it to log a warning including
the invalid content_type string and the exception details before returning None.
Use a module logger (e.g., logger = logging.getLogger(__name__)) or an existing
logger and call logger.warning(...) inside the except block, referencing the
caught exception and the content_type variable; keep the existing return None
behavior. Ensure you import logging if not present and catch both ValueError and
ContentType.DoesNotExist in the same except to log them.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: fa0ac14d-0253-4dfc-8eef-152472649849

📥 Commits

Reviewing files that changed from the base of the PR and between 1e7cfc2 and 7b9b118.

⛔ Files ignored due to path filters (11)
  • docs/assets/images/air-sim/01-topology.svg is excluded by !**/*.svg
  • docs/assets/images/air-sim/02-options.svg is excluded by !**/*.svg
  • docs/assets/images/air-sim/03-launch-ready.svg is excluded by !**/*.svg
  • docs/assets/images/air-sim/04-launch-running.svg is excluded by !**/*.svg
  • docs/assets/images/air-sim/05-launch-pod-status.svg is excluded by !**/*.svg
  • docs/assets/images/air-sim/06-launch-dhcp-log.svg is excluded by !**/*.svg
  • docs/assets/images/air-sim/07-launch-ztp-log.svg is excluded by !**/*.svg
  • docs/assets/images/air-sim/08-launch-access.svg is excluded by !**/*.svg
  • docs/assets/images/installer/19-values-preview-generated.svg is excluded by !**/*.svg
  • installer/uv.lock is excluded by !**/*.lock
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (210)
  • .github/copilot-instructions.md
  • Makefile
  • THIRD_PARTY_LICENSES.md
  • components/nautobot/nautobot-nv-config-manager/nv_config_manager/management/__init__.py
  • components/nautobot/nautobot-nv-config-manager/nv_config_manager/migrations/__init__.py
  • components/nautobot/nv_config_manager_jobs/bootstrap/load_bootstrap_data.py
  • components/nautobot/nv_config_manager_jobs/data/config_contexts.yaml
  • components/nautobot/tests/test_load_bootstrap_data.py
  • deploy/airgapped/README.md
  • deploy/airgapped/create-airgapped.sh
  • deploy/airgapped/manifests/load-airgapped-images.sh
  • deploy/helm/sample-eso-config.yaml
  • deploy/helm/sample-nv-config-manager.ini
  • deploy/helm/templates/_vault-agent.tpl
  • deploy/helm/templates/kubernetes-secrets.yaml
  • deploy/helm/templates/vault-secrets.yaml
  • deploy/helm/values-rbac-open.yaml
  • deploy/helm/values.yaml
  • deploy/scripts/setup-vm-prereqs.sh
  • development/air_sim/configs/air_trial.yaml
  • development/air_sim/template_plugins/superpod-template-plugin/README.md
  • development/air_sim/template_plugins/superpod-template-plugin/pyproject.toml
  • development/air_sim/template_plugins/superpod-template-plugin/src/nv_config_manager_superpod_templates/__init__.py
  • development/air_sim/template_plugins/superpod-template-plugin/src/nv_config_manager_superpod_templates/templates/cumulus-linux/cin-leaf/5.16.1/entrypoint/boot-script.j2
  • development/air_sim/template_plugins/superpod-template-plugin/src/nv_config_manager_superpod_templates/templates/cumulus-linux/cin-leaf/5.16.1/entrypoint/startup.yaml.j2
  • development/air_sim/template_plugins/superpod-template-plugin/src/nv_config_manager_superpod_templates/templates/cumulus-linux/cin-spine/5.16.1/entrypoint/boot-script.j2
  • development/air_sim/template_plugins/superpod-template-plugin/src/nv_config_manager_superpod_templates/templates/cumulus-linux/cin-spine/5.16.1/entrypoint/startup.yaml.j2
  • development/air_sim/template_plugins/superpod-template-plugin/src/nv_config_manager_superpod_templates/templates/cumulus-linux/oob-hleaf/5.16.1/entrypoint/boot-script.j2
  • development/air_sim/template_plugins/superpod-template-plugin/src/nv_config_manager_superpod_templates/templates/cumulus-linux/oob-hleaf/5.16.1/entrypoint/startup.yaml.j2
  • development/air_sim/template_plugins/superpod-template-plugin/src/nv_config_manager_superpod_templates/templates/cumulus-linux/oob-mleaf/5.16.1/entrypoint/boot-script.j2
  • development/air_sim/template_plugins/superpod-template-plugin/src/nv_config_manager_superpod_templates/templates/cumulus-linux/oob-mleaf/5.16.1/entrypoint/startup.yaml.j2
  • development/air_sim/template_plugins/superpod-template-plugin/src/nv_config_manager_superpod_templates/templates/cumulus-linux/oob-spine/5.16.1/entrypoint/boot-script.j2
  • development/air_sim/template_plugins/superpod-template-plugin/src/nv_config_manager_superpod_templates/templates/cumulus-linux/oob-spine/5.16.1/entrypoint/startup.yaml.j2
  • development/air_sim/template_plugins/superpod-template-plugin/src/nv_config_manager_superpod_templates/templates/cumulus-linux/superpod-demo-common/include/bridge.j2
  • development/air_sim/template_plugins/superpod-template-plugin/src/nv_config_manager_superpod_templates/templates/cumulus-linux/superpod-demo-common/include/evpn.j2
  • development/air_sim/template_plugins/superpod-template-plugin/src/nv_config_manager_superpod_templates/templates/cumulus-linux/superpod-demo-common/include/interface.j2
  • development/air_sim/template_plugins/superpod-template-plugin/src/nv_config_manager_superpod_templates/templates/cumulus-linux/superpod-demo-common/include/nve.j2
  • development/air_sim/template_plugins/superpod-template-plugin/src/nv_config_manager_superpod_templates/templates/cumulus-linux/superpod-demo-common/include/qos.j2
  • development/air_sim/template_plugins/superpod-template-plugin/src/nv_config_manager_superpod_templates/templates/cumulus-linux/superpod-demo-common/include/router.j2
  • development/air_sim/template_plugins/superpod-template-plugin/src/nv_config_manager_superpod_templates/templates/cumulus-linux/superpod-demo-common/include/service.j2
  • development/air_sim/template_plugins/superpod-template-plugin/src/nv_config_manager_superpod_templates/templates/cumulus-linux/superpod-demo-common/include/system.j2
  • development/air_sim/template_plugins/superpod-template-plugin/src/nv_config_manager_superpod_templates/templates/cumulus-linux/superpod-demo-common/include/vrf.j2
  • development/air_sim/template_plugins/superpod-template-plugin/src/nv_config_manager_superpod_templates/templates/cumulus-linux/tan-bleaf/5.16.1/entrypoint/boot-script.j2
  • development/air_sim/template_plugins/superpod-template-plugin/src/nv_config_manager_superpod_templates/templates/cumulus-linux/tan-bleaf/5.16.1/entrypoint/startup.yaml.j2
  • development/air_sim/template_plugins/superpod-template-plugin/src/nv_config_manager_superpod_templates/templates/cumulus-linux/tan-hleaf/5.16.1/entrypoint/boot-script.j2
  • development/air_sim/template_plugins/superpod-template-plugin/src/nv_config_manager_superpod_templates/templates/cumulus-linux/tan-hleaf/5.16.1/entrypoint/startup.yaml.j2
  • development/air_sim/template_plugins/superpod-template-plugin/src/nv_config_manager_superpod_templates/templates/cumulus-linux/tan-sleaf/5.16.1/entrypoint/boot-script.j2
  • development/air_sim/template_plugins/superpod-template-plugin/src/nv_config_manager_superpod_templates/templates/cumulus-linux/tan-sleaf/5.16.1/entrypoint/startup.yaml.j2
  • development/air_sim/template_plugins/superpod-template-plugin/src/nv_config_manager_superpod_templates/templates/cumulus-linux/tan-spine/5.16.1/entrypoint/boot-script.j2
  • development/air_sim/template_plugins/superpod-template-plugin/src/nv_config_manager_superpod_templates/templates/cumulus-linux/tan-spine/5.16.1/entrypoint/startup.yaml.j2
  • development/mock_topology/context/__init__.py
  • development/mock_topology/context/air_superpod/README.md
  • development/mock_topology/context/air_superpod/devices/oob-mgmt-server.json
  • development/mock_topology/context/air_superpod/devices/su00-cin-spine01.json
  • development/mock_topology/context/air_superpod/devices/su00-cin-spine02.json
  • development/mock_topology/context/air_superpod/devices/su00-control01.json
  • development/mock_topology/context/air_superpod/devices/su00-control02.json
  • development/mock_topology/context/air_superpod/devices/su00-oob-spine01.json
  • development/mock_topology/context/air_superpod/devices/su00-oob-spine02.json
  • development/mock_topology/context/air_superpod/devices/su00-tan-spine01.json
  • development/mock_topology/context/air_superpod/devices/su00-tan-spine02.json
  • development/mock_topology/context/air_superpod/devices/su01-cin-leaf-r01.json
  • development/mock_topology/context/air_superpod/devices/su01-cin-leaf-r02.json
  • development/mock_topology/context/air_superpod/devices/su01-compute-tray-r01.json
  • development/mock_topology/context/air_superpod/devices/su01-compute-tray-r02.json
  • development/mock_topology/context/air_superpod/devices/su01-oob-hleaf01.json
  • development/mock_topology/context/air_superpod/devices/su01-oob-hleaf02.json
  • development/mock_topology/context/air_superpod/devices/su01-oob-mleaf01.json
  • development/mock_topology/context/air_superpod/devices/su01-oob-mleaf02.json
  • development/mock_topology/context/air_superpod/devices/su01-storage01.json
  • development/mock_topology/context/air_superpod/devices/su01-tan-bleaf01.json
  • development/mock_topology/context/air_superpod/devices/su01-tan-bleaf02.json
  • development/mock_topology/context/air_superpod/devices/su01-tan-hleaf01.json
  • development/mock_topology/context/air_superpod/devices/su01-tan-hleaf02.json
  • development/mock_topology/context/air_superpod/devices/su01-tan-sleaf01.json
  • development/mock_topology/context/air_superpod/devices/su01-tan-sleaf02.json
  • development/mock_topology/context/air_superpod/locations.yaml
  • development/mock_topology/context/air_superpod/prefixes.yaml
  • development/mock_topology/context/air_trial/README.md
  • development/mock_topology/context/air_trial/devices/oob-mgmt-server.json
  • development/mock_topology/context/air_trial/devices/oob-mleaf-01.json
  • development/mock_topology/context/air_trial/devices/tan-leaf-01.json
  • development/mock_topology/context/air_trial/devices/tan-leaf-02.json
  • development/mock_topology/context/air_trial/devices/tan-leaf-03.json
  • development/mock_topology/context/air_trial/devices/tan-leaf-04.json
  • development/mock_topology/context/air_trial/devices/tan-leaf-05.json
  • development/mock_topology/context/air_trial/locations.yaml
  • development/mock_topology/context/air_trial/prefixes.yaml
  • development/mock_topology/context/dgx_cloud/devices/core1-cg1-cp1-tan1-dc01.json
  • development/mock_topology/context/dgx_cloud/devices/core1-cg2-cp1-tan1-dc01.json
  • development/mock_topology/context/dgx_cloud/devices/core1-cp1-smn1-dc01.json
  • development/mock_topology/context/dgx_cloud/devices/core2-cg1-cp1-tan1-dc01.json
  • development/mock_topology/context/dgx_cloud/devices/core2-cg2-cp1-tan1-dc01.json
  • development/mock_topology/context/dgx_cloud/devices/core2-cp1-smn1-dc01.json
  • development/mock_topology/context/dgx_cloud/devices/leaf1-cno1-cp1-tan1-dc01.json
  • development/mock_topology/context/dgx_cloud/devices/leaf1-cp1-smn1-dc01.json
  • development/mock_topology/context/dgx_cloud/devices/leaf1-hss1-cp1-tan1-dc01.json
  • development/mock_topology/context/dgx_cloud/devices/leaf2-cno1-cp1-tan1-dc01.json
  • development/mock_topology/context/dgx_cloud/devices/leaf2-cp1-smn1-dc01.json
  • development/mock_topology/context/dgx_cloud/devices/leaf2-hss1-cp1-tan1-dc01.json
  • development/mock_topology/context/dgx_cloud/devices/spine1-cp1-smn1-dc01.json
  • development/mock_topology/context/dgx_cloud/devices/spine2-cp1-smn1-dc01.json
  • development/mock_topology/context/dgx_cloud/devices/spine3-cno1-cp1-tan1-dc01.json
  • development/mock_topology/context/dgx_cloud/devices/spine4-cno1-cp1-tan1-dc01.json
  • development/mock_topology/context/dgx_cloud/devices/spine4-hss1-cp1-tan1-dc01.json
  • development/mock_topology/context/superpod/devices/a04-u44-p01-tor-01.json
  • development/mock_topology/context/superpod/devices/a08-u28-p01-oobspine-01.json
  • development/mock_topology/context/superpod/devices/a08-u32-p01-cleaf-01.json
  • development/mock_topology/context/superpod/devices/a08-u44-p01-mleaf-01.json
  • development/mock_topology/context/superpod/devices/a09-u28-p01-bleaf-01.json
  • development/mock_topology/context/superpod/devices/a09-u32-p01-sleaf-01.json
  • development/mock_topology/context/superpod/devices/a09-u36-p01-spine-01.json
  • development/mock_topology/context/superpod/devices/a09-u44-p01-pleaf-01.json
  • development/mock_topology/jobs/designs/devices.yaml.j2
  • development/mock_topology/jobs/designs/interfaces.yaml.j2
  • development/mock_topology/jobs/designs/ip_addresses.yaml.j2
  • development/mock_topology/jobs/designs/managed_devices.yaml.j2
  • development/mock_topology/jobs/designs/roles.yaml.j2
  • development/mock_topology/jobs/mock_topology_design.py
  • docs/README.md
  • docs/api-specs/temporal.openapi.json
  • docs/fern/docs.yml
  • docs/getting-started/index.mdx
  • docs/getting-started/local-development-quick-start.mdx
  • docs/i-want-to.mdx
  • docs/index.mdx
  • docs/install/index.mdx
  • docs/install/install-airgapped.mdx
  • docs/network-ztp/upload-images.mdx
  • docs/user-guides/air-simulation/index.mdx
  • installer/README.md
  • installer/nvcm-air-sim.yaml
  • installer/pyproject.toml
  • installer/scripts/screenshot_air_sim_tui.py
  • installer/scripts/screenshot_tui.py
  • installer/src/nv_config_manager_installer/air_sim/__init__.py
  • installer/src/nv_config_manager_installer/air_sim/cli.py
  • installer/src/nv_config_manager_installer/air_sim/cloud_init.py
  • installer/src/nv_config_manager_installer/air_sim/constants.py
  • installer/src/nv_config_manager_installer/air_sim/context_topology.py
  • installer/src/nv_config_manager_installer/air_sim/installer_config.py
  • installer/src/nv_config_manager_installer/air_sim/models.py
  • installer/src/nv_config_manager_installer/air_sim/orchestrator.py
  • installer/src/nv_config_manager_installer/air_sim/prebuilt_configs.py
  • installer/src/nv_config_manager_installer/air_sim/proxy.py
  • installer/src/nv_config_manager_installer/air_sim/sim_config.py
  • installer/src/nv_config_manager_installer/air_sim/sim_manager.py
  • installer/src/nv_config_manager_installer/air_sim/topology.py
  • installer/src/nv_config_manager_installer/cli.py
  • installer/src/nv_config_manager_installer/deployer.py
  • installer/src/nv_config_manager_installer/schema.py
  • installer/src/nv_config_manager_installer/secrets.py
  • installer/src/nv_config_manager_installer/tui/air_sim/__init__.py
  • installer/src/nv_config_manager_installer/tui/air_sim/app.py
  • installer/src/nv_config_manager_installer/tui/air_sim/app.tcss
  • installer/src/nv_config_manager_installer/tui/air_sim/screens/__init__.py
  • installer/src/nv_config_manager_installer/tui/air_sim/screens/launch.py
  • installer/src/nv_config_manager_installer/tui/air_sim/screens/options.py
  • installer/src/nv_config_manager_installer/tui/air_sim/screens/topology.py
  • installer/src/nv_config_manager_installer/tui/screens/vault.py
  • installer/tests/__init__.py
  • installer/tests/air_sim/test_context_topology.py
  • installer/tests/air_sim/test_installer_config.py
  • installer/tests/air_sim/test_orchestrator.py
  • installer/tests/air_sim/test_tui_launch.py
  • installer/tests/conftest.py
  • installer/tests/test_cli.py
  • installer/tests/test_conditional_fields.py
  • installer/tests/test_deployer.py
  • installer/tests/test_helm_values.py
  • installer/tests/test_operator_versions.py
  • installer/tests/test_registry_client.py
  • installer/tests/test_schema.py
  • installer/tests/test_secrets.py
  • installer/tests/test_template_scanner.py
  • installer/tests/test_tui.py
  • pyproject.toml
  • scripts/add_spdx_headers.py
  • src/nv_config_manager/temporal/api/parameter_v1.py
  • src/nv_config_manager/temporal/client/air.py
  • src/nv_config_manager/temporal/ngc/activities/__init__.py
  • src/nv_config_manager/temporal/ngc/activities/air.py
  • src/nv_config_manager/temporal/ngc/workflows/__init__.py
  • src/nv_config_manager/temporal/ngc/workflows/air.py
  • src/tests/conftest.py
  • src/tests/temporal/api/test_parameter.py
  • src/tests/temporal/ngc/activities/test_air.py
  • src/tests/temporal/ngc/workflows/test_air_workflow.py
  • ui/src/app/workflows/aircreatesimulationworkflow/form/air-create-simulation-form.tsx
  • ui/src/app/workflows/aircreatesimulationworkflow/form/loading.tsx
  • ui/src/app/workflows/aircreatesimulationworkflow/form/page.tsx
  • ui/src/app/workflows/airdeletesimulationworkflow/form/air-delete-simulation-form.tsx
  • ui/src/app/workflows/airdeletesimulationworkflow/form/loading.tsx
  • ui/src/app/workflows/airdeletesimulationworkflow/form/page.tsx
  • ui/src/app/workflows/airvalidatesiteworkflow/form/air-validates-site-workflow-form.tsx
  • ui/src/app/workflows/airvalidatesiteworkflow/form/loading.tsx
  • ui/src/app/workflows/airvalidatesiteworkflow/form/page.tsx
  • ui/src/config/site.ts
  • ui/src/hooks/index.ts
  • ui/src/hooks/useSimulations.ts
  • ui/src/mocks/data/airSimulations.ts
  • ui/src/mocks/data/index.ts
  • ui/src/mocks/handlers/airHandlers.ts
  • ui/src/mocks/handlers/index.ts
  • ui/src/mocks/handlers/workflowHandlers.ts
  • ui/src/types/data-table.types.ts
  • ui/tests/e2e/airCreateSimulationForm.spec.ts
  • ui/tests/e2e/airDeleteSimulationForm.spec.ts
  • ui/tests/e2e/airValidateSiteForm.spec.ts
  • ui/tests/e2e/shared/apiMocks.ts
💤 Files with no reviewable changes (17)
  • deploy/helm/sample-nv-config-manager.ini
  • deploy/helm/sample-eso-config.yaml
  • deploy/scripts/setup-vm-prereqs.sh
  • components/nautobot/nv_config_manager_jobs/data/config_contexts.yaml
  • src/nv_config_manager/temporal/client/air.py
  • src/nv_config_manager/temporal/ngc/workflows/init.py
  • src/nv_config_manager/temporal/ngc/activities/init.py
  • deploy/helm/templates/kubernetes-secrets.yaml
  • src/nv_config_manager/temporal/ngc/activities/air.py
  • deploy/helm/values.yaml
  • installer/src/nv_config_manager_installer/schema.py
  • deploy/helm/templates/vault-secrets.yaml
  • docs/api-specs/temporal.openapi.json
  • src/nv_config_manager/temporal/api/parameter_v1.py
  • deploy/helm/templates/_vault-agent.tpl
  • pyproject.toml
  • deploy/helm/values-rbac-open.yaml

Comment thread installer/src/nv_config_manager_installer/air_sim/topology.py Outdated
Comment thread installer/src/nv_config_manager_installer/deployer.py Outdated
Signed-off-by: Zoe Blevins <zblevins@nvidia.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant